/**
 *Copyright (c) 2024 watereyes
 * workflow is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package com.koron.workflow.common.service.impl;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
import com.koron.common.web.bean.DepartmentTreeBean;
import com.koron.common.web.mapper.DepartmentMapper;
import com.koron.common.web.mapper.TreeMapper;
import com.koron.workflow.baseConfig.bean.DepartmentBean;
import com.koron.workflow.common.bean.StaffBean;
import com.koron.workflow.common.mapper.SynchronizationSysInfoMapper;
import com.koron.workflow.common.service.SynchronizationSysInfoService;
import com.koron.workflow.common.util.BusinessCode;
import com.koron.workflow.common.util.HttpRequestGetAndPostUtil;
import com.koron.workflow.common.util.WorkflowUtil;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.swan.bean.MessageBean;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SynchronizationSysInfoServiceImpl implements SynchronizationSysInfoService {
    private static final Logger logger = LoggerFactory.getLogger(SynchronizationSysInfoServiceImpl.class);

    // 一次最多修改数据库条数
    private static final Integer UPDATE_MAX_ROU_NUMBER = 500;

    // 是否同步comlib 库人员组织数据
    @Value("${enabledSyncBasicComlibInfo}")
    private String enabledSyncBasicComlibInfo;
    // 如果 enabledSyncBasicComlibInfo 为false，需要进行同步的人员接口url
    @Value("${syncBasicStaffUrl}")
    private String syncBasicStaffUrl;
    // 如果 enabledSyncBasicComlibInfo 为false，需要进行同步的组织接口url
    @Value("${syncBasicDepartmentUrl}")
    private String syncBasicDepartmentUrl;

    @TaskAnnotation("synchronizationStaffInfo")
    @Override
    public MessageBean synchronizationStaffInfo(SessionFactory factory) {
        logger.info("------------定时任务(同步用户信息)开始执行------------");
        MessageBean msg = MessageBean.create(BusinessCode.SUCCESS.getCode(), BusinessCode.SUCCESS.getDescription(), String.class);
        try {
            // 全部员工信息
            List<StaffBean> staffBeans = getAllStaff(factory);
            if (staffBeans != null && staffBeans.size() > 0) {
                SynchronizationSysInfoMapper mapper = factory.getMapper(SynchronizationSysInfoMapper.class);
                // 获取当前系统全部员工信息
                List<StaffBean> allStaff = mapper.getAllStaff();
                List<String> allStaffAccount = allStaff.stream()
                        .map(staffBean -> staffBean.getAccount())
                        .collect(Collectors.toList());
                // 筛选出当前 comlibAllStaff 和 allStaff 相同code list
                List<StaffBean> updateList = staffBeans.stream()
                        .filter(staffBean ->
                                allStaffAccount.contains(staffBean.getAccount()))
                        .collect(Collectors.toList());
                // 筛选出当前 comlibAllStaff 存在 allStaff 不存在的code list
                List<StaffBean> insertList = staffBeans.stream()
                        .filter(staffBean ->
                                !allStaffAccount.contains(staffBean.getAccount()))
                        .collect(Collectors.toList());
                List<StaffBean> list;
                if (updateList != null && updateList.size() > 0) {
                    for (StaffBean staffBean : updateList) {
                        // 更新员工信息
                        mapper.updateStaff(staffBean);
                    }
                    /*if (updateList.size() > UPDATE_MAX_ROU_NUMBER) {// 每次最多修改多少条数据
                        int size = updateList.size();
                        int sum = size % UPDATE_MAX_ROU_NUMBER == 0 ? size / UPDATE_MAX_ROU_NUMBER : size / UPDATE_MAX_ROU_NUMBER + 1;
                        for (int i = 0; i < sum; i++) {
                            list = updateList.stream().skip(i * UPDATE_MAX_ROU_NUMBER).limit(UPDATE_MAX_ROU_NUMBER).collect(Collectors.toList());
                            // 批量更新员工信息
                            mapper.batchUpdateStaff(list);
                        }
                    } else {
                        // 批量更新员工信息
                        mapper.batchUpdateStaff(updateList);
                    }*/
                }
                if (insertList != null && insertList.size() > 0) {
                    insertList.stream().forEach(staffBean -> {
                        staffBean.setId(WorkflowUtil.getObjectId());
                    });
                    if (insertList.size() > UPDATE_MAX_ROU_NUMBER) {// 每次最多修改多少条数据
                        int size = insertList.size();
                        int sum = size % UPDATE_MAX_ROU_NUMBER == 0 ? size / UPDATE_MAX_ROU_NUMBER : size / UPDATE_MAX_ROU_NUMBER + 1;
                        for (int i = 0; i < sum; i++) {
                            list = insertList.stream().skip(i * UPDATE_MAX_ROU_NUMBER).limit(UPDATE_MAX_ROU_NUMBER).collect(Collectors.toList());
                            // 批量新增员工信息
                            if (list.size() != mapper.batchInsertStaff(list)) {
                                factory.close(false);
                                msg.setCode(BusinessCode.FAILURE.getCode());
                                msg.setDescription("同步员工信息失败");
                                return msg;
                            }
                        }
                    } else {
                        // 批量新增员工信息
                        if (insertList.size() != mapper.batchInsertStaff(insertList)) {
                            factory.close(false);
                            msg.setCode(BusinessCode.FAILURE.getCode());
                            msg.setDescription("同步员工信息失败");
                            return msg;
                        }
                    }
                }
            } else {
                logger.info("------------定时任务(同步用户信息)获取人员数据为空------------");
            }
            msg.setDescription("同步员工信息成功");
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("同步员工信息失败", e.getMessage());
            factory.close(false);
            msg.setCode(BusinessCode.EXCEPTION.getCode());
            msg.setDescription(BusinessCode.EXCEPTION.getDescription());
        }
        logger.info("------------定时任务(同步用户信息)结束执行------------");
        return msg;
    }

    @TaskAnnotation("synchronizationDeptInfo")
    @Override
    public MessageBean synchronizationDeptInfo(SessionFactory factory) {
        logger.info("------------定时任务(同步部门信息)开始执行------------");
        MessageBean msg = MessageBean.create(BusinessCode.SUCCESS.getCode(), BusinessCode.SUCCESS.getDescription(), String.class);
        try {
            // 获取全部部门信息
            List<DepartmentBean> comlibAllDept = getAllDept(factory);
            if (comlibAllDept != null && comlibAllDept.size() > 0) {
                /*// 处理 parentId
                Integer parentId;
                for (int i = 0, size = comlibAllDept.size(); i < size; i++) {
                    parentId = Integer.parseInt(comlibAllDept.get(i).getParentmask());
                    for (int j = i - 1; j >= 0; j--) {
                        if (parentId > Integer.parseInt(comlibAllDept.get(j).getParentmask())) {
                            comlibAllDept.get(i).setParentId(comlibAllDept.get(j).getParentmask());
                            break;
                        }
                    }
                }*/
                SynchronizationSysInfoMapper mapper = factory.getMapper(SynchronizationSysInfoMapper.class);
                // 获取当前系统全部部门信息
                List<DepartmentBean> allDept = mapper.getAllDept();
                List<String> allDeptCode = allDept.stream()
                        .map(departmentBean -> departmentBean.getCode())
                        .collect(Collectors.toList());
                // 筛选出当前 departmentBeans 和 allDept 相同code list
                List<DepartmentBean> updateList = comlibAllDept.stream()
                        .filter(departmentBean ->
                                allDeptCode.contains(departmentBean.getCode()))
                        .collect(Collectors.toList());
                // 筛选出当前 departmentBeans 存在 allDept 不存在的code list
                List<DepartmentBean> insertList = comlibAllDept.stream()
                        .filter(departmentBean ->
                                !allDeptCode.contains(departmentBean.getCode()))
                        .collect(Collectors.toList());
                List<DepartmentBean> list;
                if (updateList != null && updateList.size() > 0) {
                    for (DepartmentBean bean : updateList) {
                        // 更新员工信息
                        mapper.updateDept(bean);
                    }
                    /*if (updateList.size() > UPDATE_MAX_ROU_NUMBER) {// 每次最多修改多少条数据
                        int size = updateList.size();
                        int sum = size % UPDATE_MAX_ROU_NUMBER == 0 ? size / UPDATE_MAX_ROU_NUMBER : size / UPDATE_MAX_ROU_NUMBER + 1;
                        for (int i = 0; i < sum; i++) {
                            list = updateList.stream().skip(i * UPDATE_MAX_ROU_NUMBER).limit(UPDATE_MAX_ROU_NUMBER).collect(Collectors.toList());
                            // 批量更新部门信息
                            mapper.batchUpdateDept(list);
                        }
                    } else {
                        // 批量更新部门信息
                        mapper.batchUpdateDept(updateList);
                    }*/
                }
                if (insertList != null && insertList.size() > 0) {
                    if (insertList.size() > UPDATE_MAX_ROU_NUMBER) {// 每次最多修改多少条数据
                        int size = insertList.size();
                        int sum = size % UPDATE_MAX_ROU_NUMBER == 0 ? size / UPDATE_MAX_ROU_NUMBER : size / UPDATE_MAX_ROU_NUMBER + 1;
                        for (int i = 0; i < sum; i++) {
                            list = insertList.stream().skip(i * UPDATE_MAX_ROU_NUMBER).limit(UPDATE_MAX_ROU_NUMBER).collect(Collectors.toList());
                            // 批量新增部门信息
                            if (list.size() != mapper.batchInsertDept(list)) {
                                factory.close(false);
                                msg.setCode(BusinessCode.FAILURE.getCode());
                                msg.setDescription("同步员工部门失败");
                                return msg;
                            }
                        }
                    } else {
                        // 批量新增部门信息
                        if (insertList.size() != mapper.batchInsertDept(insertList)) {
                            factory.close(false);
                            msg.setCode(BusinessCode.FAILURE.getCode());
                            msg.setDescription("同步员工部门失败");
                            return msg;
                        }
                    }
                }
            } else {
                logger.info("------------定时任务(同步部门信息)获取部门数据为空------------");
            }
            msg.setDescription("同步员工部门成功");
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("同步员工部门失败", e.getMessage());
            factory.close(false);
            msg.setCode(BusinessCode.EXCEPTION.getCode());
            msg.setDescription(BusinessCode.EXCEPTION.getDescription());
        }
        logger.info("------------定时任务(同步部门信息)结束执行------------");
        return msg;
    }

    /**
     * 获取全部员工信息
     *
     * @param factory
     * @return
     */
    private List<StaffBean> getAllStaff(SessionFactory factory) {
        String str = HttpRequestGetAndPostUtil.sendGet(syncBasicStaffUrl, null);
        if (!StringUtils.isEmpty(str)) {
            List<LinkedTreeMap> staffs = new Gson().fromJson(str, List.class);
            if (staffs != null && staffs.size() > 0) {
                List<StaffBean> staffBeans = new LinkedList<>();
                // 获取所有组织
                List<DepartmentBean> departmentBeans = factory.getMapper(SynchronizationSysInfoMapper.class).getAllDept();
                ;
                if (departmentBeans != null && departmentBeans.size() > 0) {
                    List<String> departmentids = departmentBeans.stream().map(departmentBean -> departmentBean.getId()).collect(Collectors.toList());
                    staffs.stream().forEach(staff -> {
                        Optional.ofNullable(staff.get("departmentid")).ifPresent(departmentid -> {
                            if (departmentids.contains(departmentid.toString())) {// 外键关系，departmentid必须存在
                                StaffBean bean = new StaffBean();
                                Optional.ofNullable(staff.get("id")).ifPresent(obj -> bean.setId(obj.toString()));
                                Optional.ofNullable(staff.get("name")).ifPresent(obj -> bean.setName(obj.toString()));
                                Optional.ofNullable(staff.get("code")).ifPresent(obj -> bean.setCode(obj.toString()));
                                bean.setDepartmentid(departmentid.toString());
                                Optional.ofNullable(staff.get("position")).ifPresent(obj -> bean.setPosition(obj.toString()));
                                Optional.ofNullable(staff.get("phone")).ifPresent(obj -> bean.setPhone(obj.toString()));
                                Optional.ofNullable(staff.get("mobile")).ifPresent(obj -> bean.setMobile(obj.toString()));
                                Optional.ofNullable(staff.get("email")).ifPresent(obj -> bean.setEmail(obj.toString()));
                                Optional.ofNullable(staff.get("sex")).ifPresent(obj -> bean.setSex(Integer.valueOf(obj.toString())));
                                Optional.ofNullable(staff.get("idcard")).ifPresent(obj -> bean.setIdcard(obj.toString()));
                                Optional.ofNullable(staff.get("status")).ifPresent(obj -> bean.setStatus(Integer.valueOf(obj.toString().substring(0, obj.toString().indexOf(".")))));
                                Optional.ofNullable(staff.get("account")).ifPresent(obj -> bean.setAccount(obj.toString()));
                                Optional.ofNullable(staff.get("weighting")).ifPresent(obj -> bean.setWeighting(Integer.valueOf(obj.toString().substring(0, obj.toString().indexOf(".")))));
                                Optional.ofNullable(staff.get("photourl")).ifPresent(obj -> bean.setPhotourl(obj.toString()));
                                Optional.ofNullable(staff.get("openid")).ifPresent(obj -> bean.setOpenid(obj.toString()));
                                Optional.ofNullable(staff.get("userid")).ifPresent(obj -> bean.setUserid(obj.toString()));
                                Optional.ofNullable(staff.get("departmentCode")).ifPresent(obj -> bean.setDepartmentCode(obj.toString()));
                                Optional.ofNullable(staff.get("departmentName")).ifPresent(obj -> bean.setDepartmentname(obj.toString()));
                                staffBeans.add(bean);
                            }
                        });
                    });
                }
                return staffBeans;
            }
        }
        return null;
    }

    /**
     * 获取全部部门信息
     *
     * @param factory
     * @return
     */
    private List<DepartmentBean> getAllDept(SessionFactory factory) {
        String str = HttpRequestGetAndPostUtil.sendGet(syncBasicDepartmentUrl, null);
        if (!StringUtils.isEmpty(str)) {
            List<LinkedTreeMap> departments = new Gson().fromJson(str, List.class);
            if (departments != null && departments.size() > 0) {
                List<DepartmentBean> departmentBeans = new LinkedList<>();
                departments.stream().forEach(department -> {
                    DepartmentBean bean = new DepartmentBean();
                    Optional.ofNullable(department.get("id")).ifPresent(obj -> bean.setId(obj.toString()));
                    Optional.ofNullable(department.get("name")).ifPresent(obj -> bean.setName(obj.toString()));
                    Optional.ofNullable(department.get("code")).ifPresent(obj -> bean.setCode(obj.toString()));
                    Optional.ofNullable(department.get("description")).ifPresent(obj -> bean.setDescription(obj.toString()));
                    Optional.ofNullable(department.get("sn")).ifPresent(obj -> bean.setSn(Integer.valueOf(obj.toString())));
                    Optional.ofNullable(department.get("tel")).ifPresent(obj -> bean.setTel(obj.toString()));
                    Optional.ofNullable(department.get("state")).ifPresent(obj -> bean.setState(Integer.valueOf(obj.toString().substring(0, obj.toString().indexOf(".")))));
                    Optional.ofNullable(department.get("flag")).ifPresent(obj -> bean.setFlag(Integer.valueOf(obj.toString())));
                    Optional.ofNullable(department.get("shortname")).ifPresent(obj -> bean.setShortname(obj.toString()));
                    Optional.ofNullable(department.get("parentId")).ifPresent(obj -> bean.setParentCode(obj.toString()));
//                        Optional.ofNullable(department.get("parentId")).ifPresent(obj -> bean.setParentId(obj.toString()));
                    departmentBeans.add(bean);
                });
                return new ArrayList<>(departmentBeans);
            }
        }
        return null;
    }


    /**
     * 获取 comlib数据库 全部员工信息
     *
     * @param factory
     * @param ids
     * @param type
     * @return
     */
    private List<DepartmentBean> getCommlibAllDept(SessionFactory factory, Integer[] ids, Integer type) {
        DepartmentMapper mapper = factory.getMapper(DepartmentMapper.class);
        TreeMapper treeMapper = factory.getMapper(TreeMapper.class);
        boolean dcKey = type != null && (type & 0x1000) == 0x1000;// 是否只查有维键的

        if (type == null) {
            type = -1;
        }
        /**
         * 比较器，用来进行排序，去重
         */
        TreeSet<DepartmentTreeBean> selectedSet = new TreeSet<>((o1, o2) -> {
            long dist = o1.getSeq() - o2.getSeq();
            return dist > 0 ? 1 : dist == 0 ? 0 : -1;
        });

        for (Integer objMap : ids) {
            Integer id = objMap;
            long seq = -1;
            if (id == -1)
                seq = 1l << 61;
            else
                seq = treeMapper.getBeanByForeignIdType(1, String.valueOf(id)).getSeq();

            List<DepartmentTreeBean> list = mapper.getDescendantByParentId(seq);
            // 去除类型不匹配的
            for (DepartmentTreeBean departmentTreeBean : list) {
                if ((departmentTreeBean.getFlag() & type) != 0) {
                    if (!dcKey || !departmentTreeBean.getDatacenterkey().equals(""))// 要求有维键
                    {
                        selectedSet.add(departmentTreeBean);
                    }
                }
            }
            // 加上父级路径
            selectedSet.addAll(mapper.getPathById(seq));
        }
        // 定义一个临时的堆栈
        Stack<DepartmentTreeBean> stack = new Stack<>();
        for (DepartmentTreeBean departmentTreeBean : selectedSet) {
            if (stack.isEmpty()) {
                stack.push(departmentTreeBean);
            } else {
                DepartmentTreeBean top = stack.peek();
                while (!stack.isEmpty() && departmentTreeBean.getParentmask().intValue() <= top.getParentmask().intValue()) {
                    stack.pop();
                    if (!stack.isEmpty())
                        top = stack.peek();
                }
                departmentTreeBean.setParentId(top.getId());
                stack.push(departmentTreeBean);
            }
        }
        try {
            ObjectMapper objMapper = new ObjectMapper();
            objMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            return JSON.parseArray(objMapper.writeValueAsString(selectedSet), DepartmentBean.class);
        } catch (JsonProcessingException ex) {
            ex.printStackTrace();
        }
        return null;
    }
}
